thumbnail
웹 캐시 동작 원리
Frontend
2023.04.26.

썸네일: UnsplashPaul Hanaoka

출처 : 웹 성능 최적화 기법


웹 성능 최적화 기법(루비페이퍼 사) 도서에 대한 핵심 내용과 지식을 정리한 포스트입니다. 포스트에 올라오는 내용은 도서의 일부이기 때문에 더 자세한 내용이 궁금하신 분들은 출처에서 도서를 구매해 읽어보시는 것을 추천드립니다.


6.1 캐시

  • 캐시는 요청에 빠르게 응답하기 위해 서버와 클라이언트 사이에서 응답 콘텐츠의 사본을 저장하는 공간을 의미한다. 또한 캐시를 유지하고 처리해주는 별도 서버를 캐시 서버라고 한다.
  • 웹 아키텍처에는 다양한 캐시 서버가 존재한다.
캐시종류 위치 이점
브라우저 캐시 브라우저 한 번 다운로드한 리소스들을 재사용하여 사이트 로딩을 빠르게 함.
프록시 캐시 브라우저와 ISP 조직 내 사용자들이 접속하는 웹 사이트의 리소스들을 캐시하여 네트워크 연결과 대역폭 사용률을 감소시키고 사용자의 웹 사이트 로딩을 빠르게 함
트랜스패어런트 캐시 ISP ISP는 이 캐시를 사용하여 ISP 간 대역폭이 낭비되는 것을 막는다.
리버스 프록시 캐시 ISP와 웹 서버 원본 서버로 향하는 트래픽 대역폭을 감소시키고, 사용자 응답을 개선한다.
  • 캐시 서버는 원본 서버뿐 아니라 프록시 서버, ISP 라우터 등 다양한 위치에 존재하며 네트워크 대역폭 및 비용 절감을 위해 사용된다.
  • 대표적인 웹서버인 Apache HTTP Server에서도 moc_cache, mod_cache_disk, mod_file_cache 모듈들을 활성하해 캐시 서버로 활용할 수 있고, Nginx에서도 콘텐츠 캐시 기능을 제공한다.
    • Apache Traffic Server : 아파치 소프트웨어 재단에서 재공하는 오픈 소스 웹 캐시 서버
    • Nginx : 대중적인 웹 서버 중 하나로 콘텐츠 캐시 기능 제공
    • Varnish Cache : 캐시를 통한 HTTP 가속을 목적으로 개발된 오픈 소스 소프트웨어

6.2 웹 캐시 동작 원리

  • 웹 캐시는 웹 서버와 웹 브라우저 중간에 존재하면서 최초 원본 콘텐츠 요청을 최종 서버에 보내 응답을 받은 후 그 복사본을 만들어 저장하고 사용자에게 응답한다.
  • 이후 같은 콘텐츠에 대한 요청이 오면 최종 서버에서 원본 서버를 가져오는 대신 복사본을 사용자에게 전달한다.
  • 모든 웹 콘텐츠를 캐시할 수 없기 때문에 캐시 컨트롤 과정을 필요로 한다.

6.2.1 HTTP

  • 인터넷에서 데이터를 주고받기 위한 클라이언트/서버 모델을 따르는 프로토콜
  • OSI 7 계층 모델의 마지막 7계층인 Application 레벨의 프로토콜이며 TCP/IP 위에서 동작한다.
  • 클라이언트가 특정 URL에 대한 요청(Request)을 서버 측에 보내면 서버는 요청을 처리해 URL에 해당하는 응답(response) 클라이언트에게 되돌려 보낸다.
  • 일반적으로는 HTTP를 요청하는 브라우저와 콘텐츠를 제공하는 웹 서버를 클라이언트/서버로 인식할 수 있지만, 캐시 서버와 같은 프록시 서버가 중간에 제공되면 브라우저를 클라이언트 측, 웹 서버를 서버측으로 여길수 있다.

HTTP 특징

  • 클라이언트 서버 모델로 동작
  • 비연결성이며 상태를 유지하지 않는 프로토콜이다
  • 클라이언트와 서버 간 HTTP 메시지를 주고받으며 통신한다.
  • HTTP 메시지는 헤더와 바디 부분으로 구분되어 전송된다
  • 하위 Transport Layer 프로토콜로 TCP를 사용하며, 일반적으로 80포트를 사용한다.

6.2.2 HTTP 캐시 제어 방식

  • HTTP/1.0까지는 캐시를 제어하는 명시적인 기술이 없었으며, 원본 서버 자원들이 언제까지 유효한지, 만료일 이후 해당 자원이 실제 변경되었는지 확인하는 요청/응답 헤더를 정의
  • HTTP/1.1에서 Cache-Control 헤더가 추가되어 다음과 같은 목적을 정의
    • 원본 서버로의 요청수 최소화
    • 완전한 콘텐츠를 응답할 필요 없음

Expire

  • HTTP/1.0 은 Expire 헤더를 사용해 원본 서버 콘텐츠의 유효 기간을 지정하도록 정의
  • Expire, Date 헤더를 함께 보내야 하며 Date 헤더는 요청에 대한 응답이 작성된 시점을 표시한다.
Time To Live(TTL) = Expire_value - Date_value
  • 정확한 시간 제공을 위해 서버는 글로벌 표준 시간과 동기화되어야 하며 **Network Time Protocol(NTP)**의 메커니즘을 사용해 서버 간 또는 클라이언트-서버 간 동기화를 확인해야 한다.

Cache-Control:max-age

  • HTTP/1.1 에서는 Cache-Control:max-age라는 헤더로 콘텐츠의 캐시 유지 시간을 정의
  • 캐시에 특정 콘텐츠를 얼마나 오래 유지하고 있어야 하는지 명시적으로 설정하며, 기간이 지나면 캐시 서버는 원본 서버에 해당 콘텐츠 변경 여부를 체크하거나 새로 갱신해야함
  • Expire와 차이는 Expire는 만료 일자를 지정하고, Cache-Control:max-age는 유효 기간을 지정한다.
    • 두 헤더가 모두 명시된 경우 Cache-Control을 우선 사용
  • 캐시 서버에서 Cache-Control 헤더를 사용한 동작 순서
    1. 첫 번째 요청에 대해 캐시된 응답이 없으므로, 원본 서버에 그대로 요청 전송
    2. 첫 번째 요청에 대해 원본 서버에서 응답을 생성하고 객체가 언제까지 유효한지 HTTP 헤더에 명시
    3. 캐시 서버는 해당 요청에 대한 캐시 키와 응답을 저장하고 만료일 설정 후, 요청자에게 응답 전송
    4. 이후 같은 요청을 한 시점이 만료일을 지나지 않았으면 캐시에 저장된 응답을 사용자에게 전송

Cache-Control:s-maxage

  • CDN과 같은 공용 캐시 주기를 관리한다.
  • 대부분 CDN은 동시에 사용하면 통합 관리하기가 쉽지 않아 s-maxage를 이용하면 사용중인 모든 CDN의 캐시 주기를 일괄적으로 설정하거나 변경할 수 있다.

ETag(Entity Tag)

  • 원본 서버가 리소스를 식별하기 위해 부여하는 고유 번호
  • 캐시 서버에서는 ETag를 사용해 원본 서버의 리소스가 시간이 지나 만료되었는지 캐시된 리소스를 새로 갱신해야 하는지 여부를 판단할 수 있다.
  • 따옴표 안 임의 문자들의 조합으로 구성하며 어떤 조합이 될지는 전적으로 ETag를 생성하는 원본 서버가 결정한다.
  • Strong ETag, Weak ETag 두 가지로 구분한다.
    • StrongETag는 모든 리소스에 대해 유일한 값을 가진다(생성 어려움)
    • WeakETag는 간단하게 생성할 수 있지만 신뢰도가 약해진다.

Cache-Control:public

  • public 설정시 응답은 모든 캐시 서버에 캐시될 수 있고 사용자 제한 없이 모든 사용자에게 응답이 전달될 수 있다.

Cache-Control:private

  • private 설정시, HTTP 요청에 대한 응답은 요청한 사용자만 캐시할 수 있고 CDN 같은 범용 캐시 서버에는 캐시할 수 없다.

Cache-Control:no-cache

  • 요청 헤더에서 사용되는 경우
    • 브라우저가 원본 서버나 중간에 존재하는 캐시 서버들에게 캐시된 응답을 받지 않겠다는 메시지를 전달하는 것과 같다.
    • max-age = 0을 사용하는 것과 비슷하지만 no-cache의 경우 캐시 서버는 항상 원본 서버로부터 최신 응답을 받는데 반해, max-age = 0은 콘텐츠 변경 여부를 먼저 확인하고 유효하면 캐시 값을 반환한다.
  • 응답 헤더에서 사용되는 경우
    • 원본 서버가 캐시 서버들에게 캐시된 응답을 보내기 전 원본 서버를 항상 확인하도록 강제한다

Cache-Control:no-store

  • no-store는 서버가 로컬 저장소에 메시지를 저장하지 않도록 지시한다.

6.2.3 캐시 유효성 체크

  • 사용자가 특정 웹 콘텐츠에 대한 요청을 캐시로 보냈을 때 캐시에 저장되어 있는 응답의 age가 max-age 값을 넘었다면 응답은 더 이상 신뢰할 수 없으므로 캐시는 원본 서버에 요청을 보내 새 응답을 받아야 한다.
  • 이때 원본 서버에 있는 웹 콘텐츠에 어떠한 변경이 있었다면 원본 서버는 당연히 새로운 응답을 만들어 캐시에 되돌려주고 max-age 값을 다시 설정해 캐시에 저장하도록 지시해야 한다.
    • 그러나 콘텐츠의 변경이 없는 상황에선 이런 방식은 서버 자원과 네트워크 대역폭을 낭비하므로 HTTP 표준에서는 조건부 요청 메커니즘을 제공함
  • 조건부 요청 메커니즘은 저장된 응답 TTL이 만료되었을 경우 캐시가 항상 원본 서버에서 완전한 콘텐츠를 받아오는 대신 TTL 주기 동안 콘텐츠에 변화가 있을 때에만 새 응답을 만들도록 요청한다.

시간 기반의 조건부 요청

  • 어떤 요청에 대한 원본 서버의 콘텐츠가 캐시에 저장된 후 변경되었는지 여부를 콘텐츠 최종 변경 시간 중심으로 확인하는 방법
  • 최종 변경된 날짜와 시간을 저장해서 Last-Modified 헤더에 담아 전송하여 최종 변경 시간 이후 변경 사항이 있다면 전체 응답을 다시 하도록 요청하는 방식

콘텐츠 기반의 조건부 요청

  • 어떤 요청에 대한 원본 서버의 콘텐츠가 캐시에 저장된 후 변경되었는지 여부를 콘텐츠 고윳값 중심으로 확인하는 방법
  • 주로 해시값으로 고윳값을 추출하며, 원본 서버는 ETag헤더에 고윳값을 담아 보낸다.
  • 일치하는 고윳값이 없다면 전체 응답을 주도록 요청한다.

6.2.4 캐시 콘텐츠 갱신

  • 콘텐츠가 변경되면 캐시에 저장된 복사본들을 갱신할 필요성이 있다.
  • 갱신의 2가지 방법
    • 퍼지
    • 무효화

퍼지(purge)

  • 저장소를 완전히 지우는 방식으로, 대부분 캐시 서버가 캐시를 모두 지우는 명령어, API를 제공
  • 프로모션을 하거나 새로운 페이지 오픈 시 갑작스러운 퍼지는 피하고 테스트 툴을 이용해 리소스들을 캐시에 저장해두는 것이 권장됨

무효화(invalidate)

  • 조건부 요청을 통해 캐시된 리소스들 중 변경이 있는 리소스들만 새로 갱신하는 방법
  • Cache-Control 헤더를 사용해 캐시 서버 내용을 강제로 무효화할 수 있다.

© 2022 Developer Abel, Powered By Gatsby.